package com.yjymm.edu.service.impl;

import com.alipay.api.domain.AlipayOpenAgentCancelModel;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yjymm.edu.common.*;
import com.yjymm.edu.config.AdminProperties;
import com.yjymm.edu.config.OSSConfig;
import com.yjymm.edu.config.WxConfigProperty;
import com.yjymm.edu.constant.UgtableConstant;
import com.yjymm.edu.constant.UstableConstant;
import com.yjymm.edu.exception.*;
import com.yjymm.edu.mapper.*;
import com.yjymm.edu.model.common.RoleEnum;
import com.yjymm.edu.model.dto.*;
import com.yjymm.edu.model.entity.*;
import com.yjymm.edu.model.vo.*;
import com.yjymm.edu.service.RechargeService;
import com.yjymm.edu.service.UgtableService;
import com.yjymm.edu.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yjymm.edu.service.UstableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.ResultMap;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yjymm
 * @since 2020-12-25
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    public static String FETCH_DESC_STR = "用户：{0},id：{1}于{2}提现{3}元";


    @Resource
    private UgtableMapper ugtableMapper;

    @Resource
    private RechargeService rechargeService;

    @Resource
    private GradeMapper gradeMapper;

    @Resource
    private SubjectMapper subjectMapper;

    @Resource
    private OrderMapMapper orderMapMapper;

    @Resource
    private UstableMapper ustableMapper;

    @Resource
    private UgtableService ugtableService;

    @Resource
    private UstableService ustableService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private WxConfigProperty wxConfigProperty;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private OSSClient ossClient;

    @Resource
    private OSSConfig ossConfig;

    @Resource
    private OSSUtils ossUtils;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private OrderTableServiceImpl orderTableService;

    @Resource
    private FetchLogMapper fetchLogMapper;

    @Resource
    private AdminLogMapper adminLogMapper;


    /**
     * 根据传入的code参数，获取当前微信用户的openId, session_key信息
     *
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserVO getOpenId(String code) throws Exception {
        String url = MessageFormat.format(wxConfigProperty.getLoginUrl(),
                wxConfigProperty.getAppid(),
                wxConfigProperty.getAppserect(),
                code);
        URI uri = URI.create(url);
        String forObject = restTemplate.getForObject(uri, String.class);
//        log.info(forObject);
        JacksonJsonParser jacksonJsonParser = new JacksonJsonParser();
        Map<String, Object> stringObjectMap = jacksonJsonParser.parseMap(forObject);
        //返回openId成功
        String openId = (String) stringObjectMap.get("openid");
        if (StringUtils.isBlank(openId)) {
            throw new WxLoginException();
        }
        UserVO userVO = new UserVO();
        userVO.setOpenId(openId);

        User user = User.builder().build();
        user.setOpenId(openId);
        user.setBalance(BigDecimal.valueOf(0));
        user.setFreezeBalance(BigDecimal.valueOf(0));
        user.setRoleId(RoleEnum.PARENT.getId());
        user.setGender(1);
        if (!isRegistered(openId)) {
            //用户之前已经注册过，直接返回用户openId
            userMapper.insert(user);
            BeanUtils.copyProperties(user, userVO);
        }
        userVO.setSessionKey((String) stringObjectMap.get("session_key"));
        return userVO;

    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserVO insert(UserDTO userDTO) throws SQLException {
        User user = MyBeanUtils.copyProperties2Object(userDTO, User.class);
        int insert = baseMapper.insert(user);
        if (insert != 1) {
            throw new SQLException("添加用户失败");
        }
        return null;
    }

    /**
     * 分页查询用户信息
     * 包含用户role
     * @param size
     * @param page
     * @return
     */
    @Override
    public IPage<UserVO> listPageWithWrapper(Long size, Long page, QueryWrapper<User> wrapper) {
        IPage<User> page1 = new Page<>(page, size);
        page1 = page(page1, wrapper);

        List<Role> roles = roleMapper.selectList(null);
        List<UserVO> userVOS = MyBeanUtils.converToList(page1.getRecords(), UserVO.class);
        setUserListRole(userVOS, roles);

        IPage<UserVO> page2 = new Page<>();
        page2.setCurrent(page1.getCurrent())
                .setPages(page1.getPages())
                .setSize(page1.getSize())
                .setTotal(page1.getTotal())
                .setRecords(userVOS);
        return page2;
    }

    // 为每个uservo设置role
    private void setUserListRole(List<UserVO> userVOS, List<Role> roles) {
        userVOS.stream().forEach(userVO -> {
            for (Role role : roles) {
                if (role.getId().equals(userVO.getRoleId())){
                    userVO.setRole(role);
                    break;
                }
            }
        });
    }


    /**
     * 更新用户信息
     * @param userDTO
     * @return
     * @throws SQLException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserVO updateUser(UserDTO userDTO) throws SQLException {
        User user = MyBeanUtils.copyProperties2Object(userDTO, User.class);
        if (!StringUtils.isBlank(user.getPhone())) {
            if (user.getPhone().length() != 11) {
                throw new SQLException("手机号的长度为11位");
            }
        }
        int i = baseMapper.updateById(user);
        if (i != 1) {
            throw new SQLException("更新信息失败");
        }
        return null;
    }

    /**
     * 用户上传头像
     *
     * @param id
     * @param file
     * @throws IOException
     */
    @Override
    public void uploadAvatar(Integer id, MultipartFile file) throws IOException, SQLException {
        String suffix = null;
        if (file == null || file.isEmpty()) {
            throw new FileUploadException("请选择文件上传");
        }
        // 判断文件后缀是否符合，只能上传jpg,png后缀
        if (!MediaType.IMAGE_JPEG_VALUE.equals(file.getContentType()) &&
                !MediaType.IMAGE_PNG_VALUE.equals(file.getContentType())) {
            throw new FileUploadException("文件后缀不符合要求");
        } else if (MediaType.IMAGE_JPEG_VALUE.equals(file.getContentType())) {
            suffix = "jpg";
        } else {
            suffix = "png";
        }

        // 生成随机文件名称
        String fileName = FileUploadUtils.randomFileName(suffix);
        // 上传oss
        PutObjectRequest putObjectRequest =
                new PutObjectRequest(ossConfig.getBucketName(), fileName, file.getInputStream());
        PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
        if (putObjectResult == null) {
            throw new FileUploadException("上传文件失败");
        }
        log.info("上传文件到oss成功：{}", fileName);

        // 插入数据库
        User user = User.builder().build();
        user.setId(id);
        user.setAvatar(fileName);
        int i = userMapper.updateById(user);
        if (i != 1) {
            throw new SQLException("上传头像失败");
        }

    }


    /**
     * 根据openId判断用户是否已经注册
     * @param openId
     * @return
     */
    private Boolean isRegistered(String openId) {
        Integer count = userMapper.isExists(openId);
        return count == 1 ? Boolean.TRUE : Boolean.FALSE;
    }

    private void setAvatar(List<UserVO> userVOS) {
        for (UserVO userVO : userVOS) {
            userVO.setAvatar(ossUtils.addUrlPrefix(userVO.getAvatar()));
        }
    }

    /**
     * 获取用户详细信息（不是所有的详细信息）
     * 角色，感兴趣的年级，科目
     * @param id
     * @return
     * @throws Exception
     */
    @Override
    public UserVO getDetailById(Integer id) throws Exception {
        User user = baseMapper.selectById(id);
        if (user == null) {
            throw new SQLException("该用户不存在");
        }
        UserVO userVO = MyBeanUtils.copyProperties2Object(user, UserVO.class);
        // 用户头像
        userVO.setAvatar(ossUtils.addUrlPrefix(userVO.getAvatar()));

        Role role = roleMapper.selectById(userVO.getRoleId());
        userVO.setRole(role);

        // 用户兴趣
        List<UgtableVO> ugtableVOList = ugtableService.getByUserId(id);
        userVO.setUgtableVOList(ugtableVOList);
        List<UstableVO> ustableVOList = ustableService.getByUserId(id);
        userVO.setUstableVOList(ustableVOList);

        // 用户订单数
        Integer count = orderTableService.getUserOrderCount(userVO.getId());
        if (count == null) {
            count = 0;
        }
        userVO.setOrderCount(count);

        // 用户充值订单数
        Integer recount = rechargeService.getUserRechargeCount(userVO.getId());
        userVO.setRechargeCount(recount);

        // 用户充值成功和充值失败个数
        Integer sc = rechargeService.getUserSuccessRechargeCount(userVO.getId());
        userVO.setSuccessRechargeC(sc);
        userVO.setFailRechargeC(recount - sc);
        return userVO;
    }

    @Override
    public UserVO getByOpenId(String openId) throws Exception {
        User user = userMapper.getUserByOpenId(openId);
        if (user == null) {
            throw new SQLException("该用户不存在");
        }
        return this.getDetailById(user.getId());
    }


    /**
     * 批量删除用户，伪删除
     * @param uids
     */
    @Override
    public void delete(List<Integer> uids) {
        int count = baseMapper.deleteBatchById(uids);
    }

    @Override
    @Transactional
    public void updateUsAndUg(UpdateUsUgDTO dto) throws SQLException {
        Integer userid = null;
        if (dto.getUid() != null) {
            userid = dto.getUid();
        } else {
            userid = userMapper.selectByOpenId(dto.getOpenid()).getId();
        }
        // TODO: 2021/4/6 判断是否未空
        ustableService.update(userid, dto.getSids());
        ugtableService.update(userid, dto.getGids());
    }

    /**
     * 查询用户信息
     * @param tid
     * @return
     */
    @Override
    public UserVO getTeacherDetaiById(Integer tid) throws Exception {
        List<Grade> grades = gradeMapper.selectList(null);
        Map<Integer,String> gmap = new HashMap<>();
        for (Grade grade : grades) {
            gmap.put(grade.getId(), grade.getGradeName());
        }
        Map<Integer,String> smap = new HashMap<>();
        List<Subject> subjects = subjectMapper.selectList(null);
        for (Subject subject : subjects) {
            smap.put(subject.getId(), subject.getSubjectName());
        }
        List<String> gradeT = new ArrayList<>();
        List<String> subjectT = new ArrayList<>();
        User user = userMapper.selectById(tid);
        UserVO userVO = MyBeanUtils.copyProperties2Object(user, UserVO.class);
        List<Integer> gids = ugtableMapper.selectUserInterestingGradeByUid(tid);
        List<Integer> sids = ustableMapper.selectUserInterestingSubjectByUid(tid);

        if (!CollectionUtils.isEmpty(gids)) {
            for (Integer gid : gids) {
                gradeT.add(gmap.get(gid));
            }
        }
        if (!CollectionUtils.isEmpty(sids)) {
            for (Integer sid : sids) {
                subjectT.add(smap.get(sid));
            }
        }
        userVO.setGradeTitle(gradeT);
        userVO.setSubjectTitle(subjectT);
        return userVO;
    }

    @Override
    public Integer getCount() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted",0);
        Integer integer = baseMapper.selectCount(queryWrapper);
        return integer;
    }

    /**
     * 更新用户角色，只能更新一次
     * @param dto
     */
    @Override
    public void changeRole(ChangeRoleDTO dto) {
        User user = baseMapper.selectById(dto.getId());
        if (user.getRoleId() != RoleEnum.USER.getId()) {
            throw new MyException("您已经更换过角色，操作失败");
        }
        user.setRoleId(dto.getRoleId());
        baseMapper.updateById(user);
    }
}
